﻿#建议保存编码为：bom头 + utf8

param
(
	[parameter(Mandatory = $true)]
	[ValidateNotNullOrEmpty()]
	[String]$目的ip地址,
	$端口 = 22,
	[String]$脚本文件名,
	$传入参数,
	[scriptblock]$powershell代码块 = { },
	[bool]$是第二次执行命令 = $false,
	[bool]$用winscp_强制执行字符串级别ssh命令 = $false,
	[bool]$复制主控机node_script目录到被控机 = $false
)


if ( ($IsWindows -eq $True) -or ($PSVersionTable.psversion.major -lt 6) ) #win
{
	& 'c:\ProgramData\kasini3000\0k_source.ps1'
}

if ($IsLinux -eq $True)
{
	& '/etc/kasini3000/0k_source.ps1'
}

if ($IsLinux -eq $True)
{
	Write-Error "应该使用另一个脚本！"
	exit 11
}

Write-Verbose "开始在win2linux被控机【${目的ip地址}】上执行"

if ( ($脚本文件名 -eq $null) -or ($脚本文件名 -eq '') )
{
	#这段代码在run_win2linux_key_pwd.ps1,run_win2win5985_pwd.ps1,run_linux2linux_key_pwd.ps1,k-commit.ps1
	$有脚本文件 = $false
	if ( ($powershell代码块.Ast.Extent.Text -eq '{ }') -or ($powershell代码块.Ast.Extent.Text -eq '{}') )
	{
		Write-Error "错误：没有输入脚本文件名，同时也没有输入代码块"
		exit 15
	}
	else
	{
		if (& 'kcd_被控机运行的代码块_含有kcd.ps1' -输入脚本代码块 $powershell代码块)
		{
			Write-Error '错误：脚本内含有kcd等关键字'
			exit 19
		}
	}
}
else
{
	$有脚本文件 = $true
	if ( ($powershell代码块.Ast.Extent.Text -eq '{ }') -or ($powershell代码块.Ast.Extent.Text -eq '{}') )
	{

	}
	else
	{
		Write-Error "错误：有输入脚本文件名，同时有输入代码块"
		exit 16
	}

	if (Test-Path -LiteralPath $脚本文件名)
	{
		if (& 'kcd_被控机运行的脚本_含有kcd.ps1' -输入脚本文件名 $脚本文件名)
		{
			Write-Error '错误！脚本内含有kcd等关键字'
			exit 18
		}
	}
	else
	{
		Write-Error "找不到脚本文件"
		exit 17
	}
}

if ( ($IsWindows -eq $True) -or ($PSVersionTable.psversion.major -lt 6) ) #win
{
	if ( $PSVersionTable.psversion.major -ge 6)
	{

	}
	else
	{
		Write-Error "在win中连接linux，依赖powershell 6"
		exit 12
	}

	$private:ssh_key2 = "${global:kasini3000目录}\ssh_key_files_old1\id_rsa"
	if (Test-Path -LiteralPath $private:ssh_key2)
	{
		chmod 600 $private:ssh_key2
	}
	else
	{
		$private:没有sshkey = 1
	}

	$private:ssh_key1 = "$env:USERPROFILE\.ssh\id_rsa"
	if (Test-Path -LiteralPath $private:ssh_key1)
	{
		chmod 600 $private:ssh_key1
	}
	else
	{
		$private:没有sshkey++
	}

	if ($private:没有sshkey -ge 2)
	{
		$ErrorActionPreference = 'continue'
		Write-Error "错误：没找到任何ssh key。卡死你3000ssh主控机，管理ssh被控机，必须使用ssh key。退出码3`n请运行【jl建立主控机ssh秘钥1z.ps1】"
		exit 3
	}

	if ($复制主控机node_script目录到被控机 -eq $true)
	{
		& 'kctf复制主控机node_script目录脚本到当前被控机.ps1'
	}

	Write-Verbose '使用ssh秘钥1，连接开始'
	[string]$private:temp011 = ssh.exe -l root -i "$env:USERPROFILE\.ssh\id_rsa"  ${目的ip地址} -p $端口 -o PasswordAuthentication=no 'date' *>&1
	Write-Verbose $private:temp011
	if ( $private:temp011.ToLower().Contains('Permission denied'.ToLower()) )
	{
		$秘钥1连接成功 = $false
		Write-Verbose "使用ssh秘钥1，在${目的ip地址}上连接失败"
	}
	else
	{
		$秘钥1连接成功 = $true
	}

	if ( $private:temp011.ToLower().Contains('timed out'.ToLower()) )
	{
		Write-Error	 "使用ssh秘钥1，在${目的ip地址}上连接超时"
		exit 1
	}

	if ($秘钥1连接成功 -eq $true)
	{
		$private:连接111 = New-PSSession -HostName ${目的ip地址} -Port $端口 -UserName root -KeyFilePath "$env:USERPROFILE\.ssh\id_rsa"

		Write-Verbose '【连接1】连接成功。现在开始执行命令：'
		$主控机公钥sha1 = Get-FileHash -Algorithm sha1 -LiteralPath "${global:kasini3000目录}\ssh_key_files_old1\authorized_keys"
		$被控机公钥sha1 = Invoke-Command -session $private:连接111 -ScriptBlock { Get-FileHash -Algorithm sha1 -LiteralPath '/root/.ssh/authorized_keys' }
		Write-Verbose ("公钥： {0} '---' {1} " -f ${主控机公钥sha1}.Hash,${被控机公钥sha1}.Hash)
		if ($主控机公钥sha1.Hash -ne $被控机公钥sha1.Hash)
		{
			Write-Verbose "主控机-被控机之间，公钥有不同"
			Copy-Item -LiteralPath "${global:kasini3000目录}\ssh_key_files_old1\authorized_keys" -Destination '/root/.ssh/' -ToSession $private:连接111 -Force
		}

		Invoke-Command -session $private:连接111 -ScriptBlock { & '/etc/kasini3000/node_script/kasini3000/tj在被控机添加path.ps1' }

		if ( $有脚本文件 -eq $true)
		{
			Invoke-Command -session $private:连接111 -FilePath $脚本文件名 -ArgumentList $传入参数
		}
		else
		{
			Invoke-Command -session $private:连接111 -ScriptBlock $powershell代码块 -ArgumentList $传入参数
		}
		Write-Verbose '【连接1】执行命令完成，即将断开连接。'
		Remove-PSSession -Session $private:连接111
	}
	else
	{
		Write-Verbose '使用ssh秘钥2，连接开始'
		[string]$private:temp012 = ssh.exe -l root -i "${global:kasini3000目录}\ssh_key_files_old1\id_rsa"  ${目的ip地址} -p $端口 -o PasswordAuthentication=no 'date' *>&1
		Write-Verbose $private:temp012
		if ( $private:temp012.ToLower().Contains('Permission denied'.ToLower()) )
		{
			$秘钥2连接成功 = $false
			Write-Verbose "使用ssh秘钥2，在${目的ip地址}上连接失败"
		}
		else
		{
			$秘钥2连接成功 = $true
		}

		if ($秘钥2连接成功 -eq $true)
		{
			$private:连接112 = New-PSSession -HostName ${目的ip地址} -Port $端口 -UserName root -KeyFilePath  "${global:kasini3000目录}\ssh_key_files_old1\id_rsa"

			Write-Verbose '【连接2】连接成功。现在开始执行命令：'
			$主控机公钥sha1 = Get-FileHash -Algorithm sha1 -LiteralPath "${global:kasini3000目录}\ssh_key_files_old1\authorized_keys"
			$被控机公钥sha1 = Invoke-Command -session $private:连接112 -ScriptBlock { Get-FileHash -Algorithm sha1 -LiteralPath '/root/.ssh/authorized_keys' }
			Write-Verbose ("公钥： {0} '---' {1} " -f ${主控机公钥sha1}.Hash,${被控机公钥sha1}.Hash)
			if ($主控机公钥sha1.Hash -ne $被控机公钥sha1.Hash)
			{
				Write-Verbose "主控机-被控机之间，公钥有不同"
				Copy-Item -LiteralPath "${global:kasini3000目录}\ssh_key_files_old1\authorized_keys" -Destination '/root/.ssh/' -ToSession $private:连接112 -Force
			}

			Invoke-Command -session $private:连接112 -ScriptBlock { & '/etc/kasini3000/node_script/kasini3000/tj在被控机添加path.ps1' }

			if ( $有脚本文件 -eq $true)
			{
				Invoke-Command -session $private:连接112 -FilePath $脚本文件名 -ArgumentList $传入参数
			}
			else
			{
				Invoke-Command -session $private:连接112 -ScriptBlock $powershell代码块 -ArgumentList $传入参数
			}
			Write-Verbose '【连接2】执行命令完成，即将断开连接。'
			Remove-PSSession -Session $private:连接112
		}
		else
		{
			if ($是第二次执行命令 -eq $true)
			{
				Write-Error "使用ssh密码连接成功，但使用ssh秘钥连接失败"
				exit 4
			}

			& 'zd只读nodelist文件.ps1'
			$当前被控机 = $global:所有被控机 | Where-Object { $_.ip -eq $目的ip地址 }
			if ($当前被控机.ip -ne $目的ip地址)
			{
				Write-Error "错误：当前被控机获取失败 ${当前被控机}"
				exit 13
			}

			$用户名 = 'root'
			$用户密码密文 = ConvertTo-SecureString $当前被控机.当前密码 -AsPlainText -Force
			$我的登陆凭据 = New-Object System.Management.Automation.PSCredential ($用户名,$用户密码密文)
			$sftp连接参数 = New-WinSCPSessionOption -Protocol Sftp -HostName $目的ip地址 -Credential $我的登陆凭据
			$指纹 = Get-WinSCPHostKeyFingerprint -SessionOption $sftp连接参数 -Algorithm SHA-256
			$sftp连接参数.SshHostKeyFingerprint = $指纹

			Write-Verbose '使用ssh密码，连接开始'
			$private:连接3 = New-WinSCPSession -SessionOption $sftp连接参数
			if ($private:连接3 -eq $null)
			{
				Write-Error "使用ssh密码，在${目的ip地址}上连接失败"
				exit 2
			}
			else
			{
				$密码连接成功 = $true
				Write-Verbose '使用ssh密码，连接成功。'
			}

			if ($密码连接成功 -eq $true)
			{
				#检测ps安装，推送公钥。
				if (Test-WinSCPPath -WinSCPSession $private:连接3 -Path '/usr/bin/pwsh')
				{
					Write-Verbose '【连接3】报告：被控机上有pwsh。'
					$检测subsystemcmd = "/usr/bin/pwsh -c `"Select-String -Pattern 'Subsystem.*powershell.*/usr/bin/pwsh' -LiteralPath '/etc/ssh/sshd_config' -Quiet -CaseSensitive `" "
					$sshd内是否有subsystem = Invoke-WinSCPCommand -WinSCPSession $private:连接3 -Command $检测subsystemcmd
					if ($sshd内是否有subsystem.Output -eq $false)
					{
						Write-Verbose "在${目的ip地址}上，sshd_config文件的subsystem配置错误"
						& 'zkj_install_powershell_从win主控机到linux被控机.ps1'  -目的ip地址 $目的ip地址
					}
					else
					{
						Write-Verbose "在${目的ip地址}上，sshd_config文件的subsystem配置正确"
						if (Test-WinSCPPath -WinSCPSession $private:连接3 -Path '/etc/kasini3000')
						{

						}
						else
						{
							Invoke-WinSCPCommand -WinSCPSession $private:连接3 -Command " mkdir '/etc/kasini3000' "
						}
					}

					if ($用winscp_强制执行字符串级别ssh命令 -eq $true)
					{
						Write-Verbose '【连接3】现在开始执行命令：'
						if ( $有脚本文件 -eq $true)
						{
							Write-Error "使用ssh密码，在${目的ip地址}上连接成功。`n错误：`n使用ssh密码时，无法远程执行【脚本】和【参数】，只能远程执行【命令】。"
							exit 22
						}
						else
						{
							Invoke-WinSCPCommand -WinSCPSession $private:连接3 -Command "/usr/bin/pwsh -c $powershell代码块 "
						}
						Write-Verbose '【连接3】执行命令完成。'
					}
				}
				else
				{
					Write-Verbose "在${目的ip地址}上，未安装pwsh"
					& 'zkj_install_powershell_从win主控机到linux被控机z.ps1'  -目的ip地址 $目的ip地址
				}
				Remove-WinSCPSession -WinSCPSession $private:连接3

				#推送秘钥，故意写成并使用独立脚本。
				Write-Verbose '推送ssh公钥开始'
				& 'winscp复制主控机公钥到被控机_win2linux_pwd.ps1' -被控机ip地址 $目的ip地址 -被控机ssh密码明文 $(${当前被控机}.当前密码)
				Write-Verbose '推送ssh公钥完毕，即将断开连接。'

			}
			& 'run_win2linux_key_pwd.ps1' -目的ip地址 $目的ip地址  -端口 $端口  -脚本文件名 $脚本文件名  -传入参数 $传入参数 -powershell代码块 $powershell代码块 -是第二次执行命令 $true
		}
	}
}

Write-Verbose "完成在win2linux被控机【${目的ip地址}】上执行"
exit 0
